function mexHIDScout
% Give a grapical summary and comparison of connected HID devices.
% @details
% mexHIDScout() shows a summary of the proerties for each HID device
% connected to the computer.  It uses the mexHID() mex function to access
% the devices.  Buttons at the top of the figure allow the user to view
% each device and its inputs, live.  Each "open" button simply opens a
% device and invokes the mexHIDPlotter() viewing function for that device.
% Each "exclusive" button attempts to open a device and prevents other
% programs, including the operating system from receiving inputs from the
% device as long as the mexHIDPlotter() is still open.  Exclusive access
% may be most useful for mouse and keyboard devices, which can cause
% confusion when used by multiple programs.
%

f = figure('NumberTitle', 'off', 'Name', mfilename, ...
    'ToolBar', 'none', 'MenuBar', 'none', ...
    'DeleteFcn', @terminateOnFigureClose);
sg = ScrollingControlGrid(f);

% get info about all devices
%  sort by usage page and usage
mexHID('initialize');
devices = mexHID('summarizeDevices');
usageTotal = 256*[devices.PrimaryUsagePage] + [devices.PrimaryUsage];
[sorted, order] = sort(usageTotal);
devices = devices(order);

% supplement device properties with some usage names
for jj = 1:length(devices)
    devices(jj).PrimaryUsagePageName = mexHIDUsage.nameForPageNumber( ...
        devices(jj).PrimaryUsagePage);

    devices(jj).PrimaryUsageName = mexHIDUsage.nameForUsageNumberOnPage( ...
        devices(jj).PrimaryUsage, devices(jj).PrimaryUsagePage);
end

% show property names down the left column
%   and each device in its own column
props = sort(fieldnames(devices));
for ii = 1:length(props)
    % property name label
    sg.newControlAtRowAndColumn(ii+2, 1:3, ...
        'Style', 'text', 'String', props{ii}, ...
        'HorizontalAlignment', 'left', ...
        'FontSize', 8);
    
    % device property values
    for jj = 1:length(devices)
        val = devices(jj).(props{ii});
        if isempty(val)
            str = '-';
        elseif isnumeric(val)
            str = num2str(val);
        elseif ischar(val)
            str = val;
        else
            sz = size(val);
            str = class(val);
        end
        sg.newControlAtRowAndColumn(ii+2, 3+jj, ...
            'Style', 'text', 'String', str, ...
            'HorizontalAlignment', 'center', ...
            'FontSize', 8);
    end
end

% show an "open" button for each device near the top
for jj = 1:length(devices)
    sg.newControlAtRowAndColumn(1, 3+jj, ...
        'Style', 'pushbutton', 'String', 'open', ...
        'HorizontalAlignment', 'center', ...
        'FontSize', 8, ...
        'Callback', {@openMatchingDeviceAndPlotter, devices(jj), false});
end

% show a "exclusive" button for each device near the top
for jj = 1:length(devices)
    sg.newControlAtRowAndColumn(2, 3+jj, ...
        'Style', 'pushbutton', 'String', 'exclusive', ...
        'HorizontalAlignment', 'center', ...
        'FontSize', 8, ...
        'Callback', {@openMatchingDeviceAndPlotter, devices(jj), true});
end

% let the scrolling control grid position all controls at once
sg.repositionControls;

% User may click to "open" different devices and view their element
% values live.  All viewing figures can update concurrently, as long as we
% keep calling mexHID('check').  Keep calling it while the mexHIDScout
% figure is open.
while ishandle(f)
    mexHID('check');
    mglWaitSecs(.001);
    drawnow;
end

function openMatchingDeviceAndPlotter(f, event, propStruct, isExclusive)
deviceID = mexHID('openMatchingDevice', propStruct, isExclusive);
if deviceID < 0
    disp(sprintf('could not open device(%d)', deviceID));
else
    f = mexHIDPlotter(deviceID);
    set(f, 'DeleteFcn', {@closeDeviceOnPlotterClose, deviceID});
end

function closeDeviceOnPlotterClose(f, event, deviceID)
mexHID('stopQueue', deviceID);
mexHID('closeQueue', deviceID);
mexHID('closeDevice', deviceID);

function terminateOnFigureClose(f, event)
mexHID('terminate');